package newnes.io.memory;

/**
 * @(#)Memory.java
 *
 *
 * @author DG
 * @version 1.00 2009/3/28
 */
 
import java.nio.ByteBuffer;

public abstract class Memory {
	private ByteBuffer memoryBuffer;
	private int memory_size;
	private int mirror_mask;
	private AddressSpace addressSpace;
	
	
	public Memory(){
		memory_size = 0;
	}
	
	
	/**
	 *Creates a new memory object and initializes it's byte buffer
	 */
	public Memory(int size){
		initializeMemory(size);
		
	}
	
	/**
	 *Initialize this block of memory.
	 *Must be called before any writing or reading can be done
	 *unless the overloaded constructor is called.
	 */
	public void initializeMemory(int size){
		memoryBuffer = ByteBuffer.allocate(size);	
		memory_size = size;
		if(addressSpace != null){
			addressSpace.setEndAddress(addressSpace.getStartAddress()+size);
		}
		addressSpace = new AddressSpace(0,size);
		mirror_mask = 0xFFFFFFFF;
	}
	
	/**
	 *Write to this memory segment.
	 *This returns a status code.
	 *-1 = writing disabled
	 *0  = attempted to write to an undefined address
	 *1  = success
	 */
	public abstract int writeToMemory(int address,byte value);
	
	/**
	 *Read from this memory segment.
	 */
	public abstract int readFromMemory(int address) throws IndexOutOfBoundsException;
	
	/**
	 *Set the range of memory addresses
	 *This cannot be called before initializeMemory as there is no guarantee that the value of
	 *the ending address will be correct.
	 */
	public void setRange(int start_address, int end_address){
		addressSpace = new AddressSpace(start_address, end_address);
	}
	
	/**
	 *Set the range of memory addresses
	 *This cannot be called before initializeMemory as there is no guarantee that the value of
	 *the ending address will be correct.
	 */
	public void setRange(AddressSpace addressRange){
		addressSpace = addressRange;
	}
	
	public AddressSpace getAddressSpace(){
		return addressSpace;
	}
	/**
	 *Set the mask to use for addresses in this address space.
	 *Must be set after initialization.
	 */
	public void setAddressMask(int mask){
		mirror_mask = mask;
	}
	
	/**
	 *Returns the mask for addresses
	 *Useful for mirroring memory across the address space
	 */
	public int getAddressMask(){
		return mirror_mask;
	}
	
	/**
	 *Return the byte buffer backing up this memory.
	 */
	public ByteBuffer getMemoryBuffer(){
		return memoryBuffer;
	}
	
	/**
	 *Return the size of this memory block.
	 */
	public int getSize(){
		return memory_size;	
	}
}
